#include <boost/test/unit_test.hpp>
#include "Thread.hpp"
#include <iostream>
#include <windows.h>//sleep test requirement

//TODO: GetState, GetID TEST
//TODO: un thread devrait contenir une seul fonction (get/set)

/*
Every thread now need a ThreadJob to execute
The user will have to define this kind of class/fonction
And pass it like to the Thread->Start(ThreadJob * Job) function
*/
class TestJob1 : public ThreadJob
{
	virtual void * DoWork()
	{
		Sleep(1000);
		std::cout << "TESTJOBTEST1" << std::endl;
		return 0;
	}
};

class TestJob2 : public ThreadJob
{
	virtual void * DoWork()
	{
		Sleep(1000);
		std::cout << "TESTJOBTEST2" << std::endl;
		return 0;
	}
};

BOOST_AUTO_TEST_CASE(simple_thread)
{
	Thread *t = new Thread();
	TestJob1 * test1 = new TestJob1();
	TestJob2 * test2 = new TestJob2();
	BOOST_CHECK(t->Start(test1));
	BOOST_CHECK(!t->Start()); //wont execute
	BOOST_CHECK(t->Join());

	
	BOOST_CHECK(t->Restart());
	t->SetThreadJob(test2);
	BOOST_CHECK(!t->Start());
	BOOST_CHECK(!t->Restart());
	BOOST_CHECK(t->Join());

	BOOST_CHECK(t->Start());
	BOOST_CHECK(!t->Restart());
	BOOST_CHECK(t->Join());

	delete t, test1,test2;
}

BOOST_AUTO_TEST_CASE(simple_thread_management)
{
	Thread *t = new Thread();;
	Thread * t1 = new Thread();;
	TestJob1 * test = new TestJob1();
	
	ThreadManager * tm = t->getManager();
	
	//is the thread already added to the manager?
	BOOST_CHECK(tm->Find(t));

	BOOST_CHECK(t->Start(test));
	BOOST_CHECK(t->Join());

	
	BOOST_CHECK(tm->Find(t1));

	delete t,t1,tm,test;
}

BOOST_AUTO_TEST_CASE(thread_manager)
{
	Thread *t = new Thread();

	ThreadManager * tm = t->getManager();

	//test multiple thread, avec stop et join
	BOOST_CHECK(tm->Find(t));
	tm->Add(t);
	BOOST_CHECK(tm->Find(t));
	tm->Remove(t);
	BOOST_CHECK(!tm->Find(t));
	tm->Remove(t);
	BOOST_CHECK(!tm->Find(t));

	delete t,tm;
}

BOOST_AUTO_TEST_CASE(thread_multiple_error)
{
	Thread *t = new Thread();
	TestJob1 * test = new TestJob1();

	//useless STOP test(View hpp file, stop doesn't really works with pthread32)
	BOOST_CHECK(t->Start(test));
	BOOST_CHECK(t->Stop());
	BOOST_CHECK(!t->Stop());
	BOOST_CHECK(!t->Stop());
	//BOOST_CHECK(t->Join()); //Should be BOOST_CHECK(!t->Join()); but Stop function doesnt work with pthread32

	BOOST_CHECK(t->Start(test));
	BOOST_CHECK(!t->Start(test)); //Can't start 2 thread at once 
	BOOST_CHECK(t->Join());

	//join test
	BOOST_CHECK(t->Start(test));
	BOOST_CHECK(t->Join());
	BOOST_CHECK(!t->Join()); 
	BOOST_CHECK(!t->Stop()); 

	delete t,test;
}

BOOST_AUTO_TEST_CASE(thread_multiple_with_manager)
{
	Thread *t = NULL;
	Thread  *t1 = NULL; 
	Thread  *t2 = NULL; 
	Thread  *t3 = NULL; 

	t = new Thread();
	t1 = new Thread();
	t2 = new Thread();

	TestJob1 * test = new TestJob1();

	ThreadManager * tm = t->getManager();
	BOOST_CHECK(tm->Find(t));
	BOOST_CHECK(tm->Find(t1));
	BOOST_CHECK(tm->Find(t2));

	BOOST_CHECK(t->Start(test));
	BOOST_CHECK(t1->Start(test));
	BOOST_CHECK(t2->Start(test));
	BOOST_CHECK(t->Join());
	BOOST_CHECK(t1->Join());
	BOOST_CHECK(t2->Join());

	t3 = t2;
	delete t,t1,t2;

	BOOST_CHECK(tm->Find(t3));

	delete t3,test;

}

BOOST_AUTO_TEST_CASE(thread_id)
{
	Thread *t = new Thread();
	Thread *t1 = new Thread();

	TestJob1 * test = new TestJob1();

	//BOOST_CHECK(t->IsThreadEqual(t1->GetId())); //This test is useless, both id are NULL
	BOOST_CHECK(t->Start(test));
	BOOST_CHECK(t->Join());
	BOOST_CHECK(!t->IsThreadEqual(t1->GetId()));

	delete t,t1,test;
}


/* OLD Thread Helper Function C Style


//fonction a passer au thread Start 
void * test(void * arg)
{

	Sleep(6000);
	std::cout << "test " << (char*)arg << std::endl;
	return 0;
}
*/